﻿namespace ShadowCode.Injection.Injections;
public class ReplaceGeneric(INamedTypeSymbol serviceType, INamedTypeSymbol tmplementType)
{
    private readonly INamedTypeSymbol tmplementType = tmplementType;
    private readonly INamedTypeSymbol serviceType = serviceType;
    private INamedTypeSymbol? resType;

#if code
public class MyClass<T1, T2> : IDictionary<T2 , T1>
{          
    [AddService<IDictionary<string, int>>(ServiceLifetime.Singleton, Index = 10)]
    [AddService<IDictionary<string, object>>(ServiceLifetime.Transient, Keyed = "key")]
    [AddService<IDictionary<string, string>>(ServiceLifetime.Scoped)]
    public MyClass(){}
}
#endif

    public INamedTypeSymbol TmplementType => resType ??= GetTmplementType();

    private INamedTypeSymbol GetTmplementType()
    {
        if (!tmplementType.IsGenericType || tmplementType.EqualsDefault(serviceType))
            return tmplementType;

        /*
        *  MyClass<T1, T2>      MyClass<object, string>
        *  serviceType      IDictionary<string, object>  
        *  targetType       IDictionary<T2    , T1>
        */

        var targetType = FindTargetType();
        var typeArguments = GetTypes(targetType).ToArray();
        return tmplementType.Construct(typeArguments);
    }


    private IEnumerable<ITypeSymbol> GetTypes(INamedTypeSymbol targetType)
    {
        var map = targetType.TypeArguments
            .Select((t, i) => (t, i))
            .ToDictionary(x => x.t.Name, x => x.i);

        foreach (var item in tmplementType.TypeParameters)
        {
            if (map.TryGetValue(item.Name, out int index))
                yield return serviceType.TypeArguments[index];
        }
    }

    private INamedTypeSymbol FindTargetType()
    {
        var serviceType = this.serviceType.OriginalDefinition;
        var items = GetBaseTypes(tmplementType)
            .Concat(tmplementType.AllInterfaces);

        foreach (var item in items)
        {
            var original = item.OriginalDefinition;
            if (original.EqualsDefault(serviceType))
                return item;
        }
        return tmplementType;
        //var msg = $"查找 {this.serviceType} 和 {tmplementType} 的继承关系失败！";
        //throw Error.Unexpected.CreateError(msg, attributeSyntax);
    }

    private IEnumerable<INamedTypeSymbol> GetBaseTypes(INamedTypeSymbol namedType)
    {
        var baseType = namedType.BaseType;
        while (baseType != null)
        {
            yield return baseType;
            baseType = baseType.BaseType;
        }
    }
}